goroutines 是類似 thread 的東西,但它比 thread 還輕量.它被視為一個獨立的工作單位.
一般呼叫 main function 裡面的程式會造順序執行.
package main
import (
"fmt"
)
func main() {
showMessage("start")
showMessage("1")
showMessage("2")
showMessage("3")
showMessage("4")
showMessage("end")
fmt.Println("done")
}
func showMessage(msg string) {
fmt.Println(msg)
}
印出
start
1
2
3
4
end
done
建立一個 goroutine 就是在使用 function 面前再加上 go 關鍵字.
下面的例子 main function 不會等 goroutine 回傳結果,還沒等 goroutine 印出數字時,程式就會結束了.
所以加上 fmt.Scanln(&input) 讓程式暫停,等隨便按了一個鍵後再按 Enter main function 才會結束.
每次數字印出的順序都會不一樣就看哪個 goroutine 先執行完,所以這些 goroutine 是同時在進行工作的.
package main
import (
"fmt"
)
func main() {
showMessage("start")
go showMessage("1")
go showMessage("2")
go showMessage("3")
go showMessage("4")
showMessage("end")
var input string
fmt.Scanln(&input)
fmt.Println("done")
}
func showMessage(msg string) {
fmt.Println(msg)
}
印出
start
end
2
4
3
1
(Enter)
done
由於 goroutine 會同時執行,所以有用到共用的資源時,執行順序有可能會影響到最後的結果
package main
import "fmt"
func main() {
sum := 10
go func() { sum += 3 }()
go func() { sum -= 5 }()
go func() { sum *= 2 }()
var input string
fmt.Scanln(&input)
fmt.Println(sum)
}
像上面的範例排列組合有幾種,每次執行有可能出現不同答案
(10 + 3 - 5) * 2 = 16
10 * 2 + 3 - 5 = 18
(10 + 3) * 2 - 5 = 21
...
在 The Go Programming Language 這本書有寫這個範例,執行的時候會先看到 spinner function 一直轉圈圈,
直到算出 fibonacci 數之後才會停止印出結果.代表說這兩件事是同時在做的也就是 concurrency 的概念.
package main
import (
"fmt"
"time"
)
func main() {
go spinner(100 * time.Millisecond)
const n = 45
fibN := fib(n)
fmt.Printf("\rFibonacci(%d) = %d \n", n, fibN)
}
func spinner(delay time.Duration) {
for {
for _, r := range `-\|/` {
fmt.Printf("\r%c", r)
time.Sleep(delay)
}
}
}
func fib(x int) int {
if x < 2 {
return x
}
return fib(x-1) + fib(x-2)
}